import java.util.List;

/**
 120.给定一个三角形，找出自顶向下的最小路径和。
 每一步只能移动到下一行中相邻的结点上。
 相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
 例如，给定三角形：
 [
 [2],
 [3,4],
 [6,5,7],
 [4,1,8,3]
 ]
 自顶向下的最小路径和为 11（即，2 + 3 + 5 + 1 = 11）。
 如果你可以只使用 O(n) 的额外空间（n 为三角形的总行数）来解决这个问题，那么你的算法会很加分。
 */

/*
方法一：动态规划
思路与算法
我们用 f[i][j]表示从三角形顶部走到位置 (i,j) 的最小路径和。
这里的位置 (i,j)指的是三角形中第i行第j列（均从0开始编号）的位置。
由于每一步只能移动到下一行「相邻的节点」上，因此要想走到位置 (i,j)，
上一步就只能在位置 (i−1,j−1) 或者位置 (i−1,j)。
我们在这两个位置中选择一个路径和较小的来进行转移，状态转移方程为：
f[i][j]=min⁡(f[i−1][j−1],f[i−1][j])+c[i][j]
其中 c[i][j]表示位置 (i,j)对应的元素值。
注意第i行有 i+1个元素，它们对应的 j 的范围为[0,i]。
当 j=0或 j=i时，上述状态转移方程中有一些项是没有意义的.

细节
状态转移方程的边界条件是什么？由于我们已经去除了所有「没有意义」的状态，因此边界条件可以定为：
f[0][0]=c[0][0]
即在三角形的顶部时，最小路径和就等于对应位置的元素值。这样一来，我们从 1开始递增地枚举 i，
并在 [0,i] 的范围内递增地枚举 j，就可以完成所有状态的计算。
复杂度n方
 */
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] f = new int[n][n];

        //边界
        f[0][0] = triangle.get(0).get(0);

        //状态转移
        for (int i = 1; i < n; ++i) {
            f[i][0] = f[i - 1][0] + triangle.get(i).get(0);
            for (int j = 1; j < i; ++j) {
                f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + triangle.get(i).get(j);
            }
            f[i][i] = f[i - 1][i - 1] + triangle.get(i).get(i);
        }

        int minTotal = f[n - 1][0];
        for (int i = 1; i < n; ++i) {
            minTotal = Math.min(minTotal, f[n - 1][i]);
        }
        return minTotal;
    }
}